﻿using System;
using System.Collections.Generic;
using System.Threading;

namespace huqiang.Framework
{
    public class HFBase
    {
        /// <summary>
        /// 函数调用次数
        /// </summary>
        uint CallCount = 0;
        protected virtual string TypeName { get => "HFBase"; }
        protected virtual void Initial()
        {
        }
        protected virtual void Start()
        {
        }
        protected virtual void Update(float time)
        {
        }
        protected virtual void SubUpdate()
        {
        }
        protected virtual void LateUpdate()
        {
        }
        public virtual void Dispose()
        {
        }
        static List<HFBase> modules = new List<HFBase>();
        static int buffLen;
        static HFBase[] buffer = new HFBase[64];
        static AutoResetEvent are;
        static int mainFrame = 0;
        static int subFrame = 0;
        static bool running;
        static Thread thread;
        public static T AddModule<T>() where T : HFBase, new()
        {
            for (int i = 0; i < modules.Count; i++)
            {
                T t = modules[i] as T;
                if (t != null)
                    return t;
            }
            T hf = new T();
            modules.Add(hf);
            hf.Initial();
            return hf;
        }
        public static T GetModule<T>() where T : HFBase
        {
            for (int i = 0; i < modules.Count; i++)
            {
                T t = modules[i] as T;
                if (t != null)
                    return t;
            }
            return null;
        }
        public static HFBase GetModuleByType(Type type)
        {
            string tn = type.Name;
            for (int i = 0; i < modules.Count; i++)
            {
                if (modules[i].TypeName == tn)
                    return modules[i];
            }
            return null;
        }
        /// <summary>
        /// 通过名称查询模块
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static HFBase GetModuleByName(string type)
        {
            for (int i = 0; i < modules.Count; i++)
            {
                if (modules[i].TypeName == type)
                    return modules[i];
            }
            return null;
        }
        public static T ReleaseModule<T>() where T : HFBase
        {
            for (int i = 0; i < modules.Count; i++)
            {
                T t = modules[i] as T;
                if (t != null)
                {
                    modules.RemoveAt(i);
                    t.Dispose();
                    return t;
                }
            }
            return null;
        }
        public static HFBase ReleaseModuleByName(string type)
        {
            for (int i = 0; i < modules.Count; i++)
            {
                HFBase t = modules[i];
                if (t.TypeName == type)
                {
                    modules.RemoveAt(i);
                    t.Dispose();
                    return t; 
                }
            }
            return null;
        }
        public static void UpdateAll(float time)
        {
            mainFrame++;
            for (int i = 0; i < buffer.Length; i++)
                buffer[i] = null;
            buffLen = modules.Count;
            modules.CopyTo(buffer);
            for (int i = 0; i < buffLen; i++)
            {
                try
                {
                    var mod = buffer[i];
                    if (mod.CallCount == 0)
                        mod.Start();
                    mod.CallCount++;
                    mod.Update(time);
                }
                catch (Exception ex)
                {
                    UnityEngine.Debug.LogError(ex.StackTrace);
                }
            }
        }
        public static void LateUpdateAll()
        {
            if (are != null)
                are.Set();
            for (int i = 0; i < buffLen; i++)
            {
                try
                {
                    buffer[i].LateUpdate();
                }
                catch (Exception ex)
                {
                    UnityEngine.Debug.LogError(ex.StackTrace);
                }
            }
        }
        static void SubThread()
        {
            while (running)
            {
                if (subFrame != mainFrame)
                {
#if UNITY_EDITOR
                    UnityEngine.Profiling.Profiler.BeginThreadProfiling("HFBase", "Mission Thread");
                    UnityEngine.Profiling.Profiler.BeginSample("SubUpdateAll");
#endif
                    SubUpdateAll();
#if UNITY_EDITOR
                    UnityEngine.Profiling.Profiler.EndSample();
                    UnityEngine.Profiling.Profiler.EndThreadProfiling();
#endif
                    subFrame = mainFrame;
                }
                else are.WaitOne(1);

            }
            are.Dispose();
        }
        public static void SubUpdateAll()
        {
            for (int i = 0; i < buffLen; i++)
            {
                try
                {
                    buffer[i].SubUpdate();
                }
                catch (Exception ex)
                {
                    UnityEngine.Debug.LogError(ex.StackTrace);
                }
            }
        }

        public static void OpenSubThread()
        {
            running = true;
            are = new AutoResetEvent(false);
            thread = new Thread(SubThread);
            thread.Start();
        }
        public static void CloseSubThread()
        {
            running = false;
            thread = null;
        }
    }
}
